package com.csproj.dispatch.service;

import com.csproj.basic.domain.Site;
import com.csproj.basic.repository.SiteRepository;
import com.csproj.dispatch.BaseService;
import com.csproj.dispatch.domain.Dispatch;
import com.csproj.dispatch.domain.WarnInfo;
import com.csproj.dispatch.repository.DispatchRepository;
import com.csproj.dispatch.repository.WarnInfoRepository;
import com.csproj.dispatch.service.dto.WarnInfoDTO;
import com.csproj.dispatch.service.mapper.WarnInfoMapper;
import com.csproj.siiat.base.common.dto.BaseDTO;
import com.csproj.siiat.base.common.repository.PageableTools;
import com.csproj.siiat.base.common.repository.SortDto;
import com.csproj.siiat.base.common.util.DateUtils;
import com.csproj.siiat.config.Languagesproperties;
import com.csproj.siiat.security.SecurityUtils;
import com.csproj.system.domain.Dictionary;
import com.csproj.system.domain.Language;
import com.csproj.system.repository.DictionaryRepository;
import com.csproj.system.repository.LanguageRepository;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.persistence.criteria.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.time.LocalDate;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

/**
 * Service Implementation for managing WarnInfo.
 */
@Service
@Transactional
public class WarnInfoService extends BaseService<WarnInfoDTO> {

    private final Logger log = LoggerFactory.getLogger(WarnInfoService.class);

    private final WarnInfoRepository warnInfoRepository;

    private final WarnInfoMapper warnInfoMapper;

    private final DispatchRepository dispatchRepository;

    private final DictionaryRepository dictionaryRepository;

    private final SiteRepository siteRepository;

    private final Languagesproperties languagesproperties;
    private final LanguageRepository languageRepository;


    public WarnInfoService(WarnInfoRepository warnInfoRepository, WarnInfoMapper warnInfoMapper,
                           DispatchRepository dispatchRepository, DictionaryRepository dictionaryRepository, SiteRepository siteRepository, Languagesproperties languagesproperties, LanguageRepository languageRepository) {
        this.warnInfoRepository = warnInfoRepository;
        this.warnInfoMapper = warnInfoMapper;
        this.dispatchRepository = dispatchRepository;
        this.dictionaryRepository = dictionaryRepository;
        this.siteRepository = siteRepository;
        this.languagesproperties = languagesproperties;
        this.languageRepository = languageRepository;
    }

    /**
     * Save a warnInfo.
     *
     * @param warnInfoDTO the entity to save
     * @return the persisted entity
     */
    public WarnInfoDTO save(WarnInfoDTO warnInfoDTO) {
        log.debug("Request to save WarnInfo : {}", warnInfoDTO);
        WarnInfo warnInfo = warnInfoMapper.toEntity(warnInfoDTO);
        warnInfo = warnInfoRepository.save(warnInfo);
        warnInfoDTO = warnInfoMapper.toDto(warnInfo);
        extendDispatchInfo(warnInfoDTO);
        extendHandleUserName(warnInfoDTO);
        return warnInfoDTO;
    }

    /**
     * Get all the warnInfos.
     *
     * @return the list of entities
     */
    @Transactional(readOnly = true)
    public List<WarnInfoDTO> findAll() {
        log.debug("Request to get all WarnInfos");
        return warnInfoRepository.findAll().stream()
                .map(warnInfoMapper::toDto)
                .collect(Collectors.toCollection(LinkedList::new));
    }

    /**
     * Get all the warnInfos.
     *
     * @return the list of entities
     */
    @Transactional(readOnly = true)
    public WarnInfoDTO findOne(String id) {
        WarnInfoDTO warnInfoDTO = warnInfoMapper.toDto(warnInfoRepository.findOne(id));
        extendDispatchInfo(warnInfoDTO);
        extendHandleUserName(warnInfoDTO);
        return warnInfoDTO;
    }


    public BaseDTO insertWarnInfo(WarnInfoDTO warnInfoDTO) {
        if (warnInfoDTO.getLockCode() == null || "".equals(warnInfoDTO.getLockCode())) {
            return new BaseDTO(BaseDTO.CODE_PARAM, "lockset_no_can_not_blank", null);
        }
        // 查询关锁所绑定的调度信息
        Dispatch dispatch = dispatchRepository.
                findFirstByLockCodeAndDeletionTimeIsNullAndArriveTimeIsNullOrderByCreationTimeDesc(warnInfoDTO.getLockCode());
        if (dispatch == null)
            return new BaseDTO(BaseDTO.CODE_PARAM, "corresponding_scheduling_information_was_found", null);
        warnInfoDTO.setDispatchId(dispatch.getId());

        WarnInfo warnInfo = warnInfoMapper.toEntity(warnInfoDTO);
        warnInfo.setCreationTime(ZonedDateTime.now());
        warnInfo.setCreatorUserId(SecurityUtils.getCurrentUserId());
        warnInfo.setHandleFlag(warnInfo.isHandleFlag() == null ? false : warnInfo.isHandleFlag());//默认未处理
        warnInfo.setNoticestatus(warnInfo.getNoticestatus() == null ? "0" : warnInfo.getNoticestatus());//默认未通知
        warnInfo = warnInfoRepository.save(warnInfo);
        warnInfoDTO = warnInfoMapper.toDto(warnInfo);
        extendDispatchInfo(warnInfoDTO);
        extendHandleUserName(warnInfoDTO);

        Dictionary dictionary = dictionaryRepository.findFirstByDictionaryName("sms_enable");
        if (dictionary != null && dictionary.getItemValue() == "true") {
            Site lauchSite = siteRepository.findOne(dispatch.getLaunchsiteId());
            Site endSite = siteRepository.findOne(dispatch.getDestinationsiteId());

            if (lauchSite != null)
                sendMessage(warnInfoDTO.getId(), lauchSite.getManagerPhone(),warnInfo.getMsg());
            if (endSite != null)
                sendMessage(warnInfoDTO.getId(), endSite.getManagerPhone(),warnInfo.getMsg());
        }


        return BaseDTO.createBaseDTO(warnInfoDTO);
    }

    public void insertWarnInfoSample(WarnInfo warnInfo) {
        if (warnInfo.getLockCode() == null || "".equals(warnInfo.getLockCode())) {
            return;
        }
        // 查询关锁所绑定的调度信息
        Dispatch dispatch = dispatchRepository.
                findFirstByLockCodeAndDeletionTimeIsNullAndArriveTimeIsNullOrderByCreationTimeDesc(warnInfo.getLockCode());
        if (dispatch == null)
            return;
        warnInfo.setDispatchId(dispatch.getId());
        warnInfo.setCreationTime(ZonedDateTime.now());
        warnInfo.setCreatorUserId(SecurityUtils.getCurrentUserId());
        warnInfo.setHandleFlag(warnInfo.isHandleFlag() == null ? false : warnInfo.isHandleFlag());//默认未处理
        warnInfo.setNoticestatus(warnInfo.getNoticestatus() == null ? "0" : warnInfo.getNoticestatus());//默认未通知
        warnInfoRepository.save(warnInfo);
    }

    /**
     * 更改通知状态
     *
     * @param id
     * @param warnInfoDTO
     * @return
     */
    public BaseDTO updateWarnInfoNotices(String id, WarnInfoDTO warnInfoDTO) {
        if (id == null || id.equals("")) {
            return new BaseDTO(BaseDTO.CODE_PARAM, "warn_info_has_no_id", null);
        }
        WarnInfo warnInfo = warnInfoRepository.findOne(id);
        if (warnInfo != null) {
            warnInfo.setNoticestatus(warnInfoDTO.getNoticestatus());
            warnInfo.setLastModificationTime(ZonedDateTime.now());
            warnInfo.setLastModifierUserId(SecurityUtils.getCurrentUserId());
            warnInfo = warnInfoRepository.save(warnInfo);
            warnInfoDTO = warnInfoMapper.toDto(warnInfo);
            extendDispatchInfo(warnInfoDTO);
            extendHandleUserName(warnInfoDTO);
            return BaseDTO.createBaseDTO(warnInfoDTO);
        }
        return new BaseDTO(BaseDTO.CODE_PARAM, "warn_info_was_not_found", null);
    }

    /**
     * 处理报警信息
     *
     * @param id
     * @param warnInfoDTO
     * @return //TODO 如果未通知成功 是否允许进行处理
     */
    public BaseDTO updateWarnInfoHandle(String id, WarnInfoDTO warnInfoDTO) {
        if (id == null || id.equals("")) {
            return new BaseDTO(BaseDTO.CODE_PARAM, "warn_info_has_no_id", null);
        }

        WarnInfo warnInfo = warnInfoRepository.findOne(id);
        if (warnInfo != null) {
            warnInfo.setHandleFlag(true);
            warnInfo.setHandlereport(warnInfoDTO.getHandlereport());
            warnInfo.setHandleTime(ZonedDateTime.now());
            warnInfo.setHandleUserId(SecurityUtils.getCurrentUserId());
            warnInfo.setLastModificationTime(ZonedDateTime.now());
            warnInfo.setLastModifierUserId(SecurityUtils.getCurrentUserId());
            warnInfo = warnInfoRepository.save(warnInfo);
            warnInfoDTO = warnInfoMapper.toDto(warnInfo);
            extendDispatchInfo(warnInfoDTO);
            extendHandleUserName(warnInfoDTO);
            return BaseDTO.createBaseDTO(warnInfoDTO);
        }
        return new BaseDTO(BaseDTO.CODE_PARAM, "warn_info_was_not_found", null);
    }

    /**
     * 获取此次调度的所有报警信息
     *
     * @param dispatchId 调度信息id
     * @return
     */
    public BaseDTO searchWarnInfosOfDispatch(String dispatchId) {
        if (dispatchId == null || dispatchId.equals("")) {
            return new BaseDTO(BaseDTO.CODE_PARAM, "warn_info_has_no_id", null);
        }
        List<WarnInfoDTO> warnInfoDTOS = warnInfoRepository.findAllByDispatchIdOrderByCreationTime(dispatchId).stream().
                map(n -> {
                    WarnInfoDTO warnInfoDTO = warnInfoMapper.toDto(n);
                    extendDispatchInfo(warnInfoDTO);
                    extendHandleUserName(warnInfoDTO);
                    return warnInfoDTO;
                }).collect(Collectors.toList());
        return BaseDTO.createBaseDTO(warnInfoDTOS);
    }

    @Transactional(readOnly = true)
    public BaseDTO searchAllWarnInfoPage(Integer page, Integer limit, Map<String, Object> option) {
        if (page == null || page.equals("")) {
            page = 1;
        }
        if (limit == null || limit.equals("")) {
            limit = 10;
        }
        Pageable pageable = PageableTools.basicPage(page, limit, new SortDto("desc", "warnTime"));
        Specification<WarnInfo> dispatchSpecification = null;

        dispatchSpecification = new Specification<WarnInfo>() {
            @Override
            public Predicate toPredicate(Root<WarnInfo> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
                //设置查询条件
                List<Predicate> list = new ArrayList<Predicate>();
                if (option != null) {//存在过滤条件
                    for (Map.Entry<String, Object> km : option.entrySet()) {
                        String key = km.getKey();
                        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
                        // 关键字查询-模糊匹配报警信息
                        if ("keyWord".equals(key)) {//关键字
                            if (!StringUtils.isEmpty(km.getValue().toString())) {
                                Predicate p = criteriaBuilder.like(root.get("msg").as(String.class), "%" + km.getValue().toString() + "%");
                                list.add(p);
                            }
                        }
                        // 起点路径条件查询 需要添加
                        if ("routeId".equals(key)) {//起点路径
                            if (!StringUtils.isEmpty(km.getValue().toString())) {
//                                Predicate p = criteriaBuilder.equal(root.get("routeId").as(String.class), km.getValue().toString());
//                                list.add(p);
                                Subquery subQuery = criteriaQuery.subquery(String.class);
                                Root fromUR = subQuery.from(Dispatch.class);
                                subQuery.select(fromUR.get("id")).where(criteriaBuilder.equal(fromUR.get("routeId"), km.getValue().toString()));
                                Predicate p = criteriaBuilder.in(root.get("dispatchId")).value(subQuery);
                                list.add(p);
                            }
                        }
                        if ("containerCode".equals(key)) {//集装箱编号
                            if (!StringUtils.isEmpty(km.getValue().toString())) {
                                Subquery subQuery = criteriaQuery.subquery(String.class);
                                Root fromUR = subQuery.from(Dispatch.class);
                                subQuery.select(fromUR.get("id")).where(criteriaBuilder.equal(fromUR.get("containerCode"), km.getValue().toString()));
                                Predicate p = criteriaBuilder.in(root.get("dispatchId")).value(subQuery);
                                list.add(p);
                            }
                        }
                        if ("lockCode".equals(key)) {//锁编号
                            if (!StringUtils.isEmpty(km.getValue().toString())) {
                                Predicate p = criteriaBuilder.equal(root.get("lockCode").as(String.class), km.getValue().toString());
                                list.add(p);
                            }
                        }
                        ZoneId zoneId = ZoneId.systemDefault();

                        if ("warnTimeStart".equals(key)) {//上报时间 开启
                            if (!StringUtils.isEmpty(km.getValue().toString())) {

                                ZonedDateTime beijingDateTime = LocalDate.parse(km.getValue().toString(), formatter).atStartOfDay().atZone(zoneId);
                                Predicate p = criteriaBuilder.greaterThan(root.get("warnTime").as(ZonedDateTime.class), beijingDateTime);
                                list.add(p);
                            }
                        }
                        if ("warnTimeEnd".equals(key)) {//上报时间 结束
                            if (!StringUtils.isEmpty(km.getValue().toString())) {
                                ZonedDateTime beijingDateTime = LocalDate.parse(km.getValue().toString(), formatter).atStartOfDay().atZone(zoneId);
                                Predicate p = criteriaBuilder.lessThan(root.get("warnTime").as(ZonedDateTime.class), beijingDateTime);
                                list.add(p);
                            }
                        }
                        Map<String, Object> currentMp = new HashMap<String, Object>() {
                        };
                        List<Language> l = languageRepository.findByDefault();
                        Language first = null;
                        if (l.size() > 0) {
                            first = l.get(0);
                        }

                        if (first != null) {
                            if (first.getName().equals("zh")) {
                                currentMp = languagesproperties.getZh();
                            } else if (first.getName().equals("en")) {
                                currentMp = languagesproperties.getEn();

                            } else if (first.getName().equals("pu")) {
                                currentMp = languagesproperties.getPu();
                            }
                        }
                        if ("warnType".equals(key)) {//报警类型
                            String warnMsg = "";
                            switch (km.getValue().toString())
                            {
                                case "1":
                                    warnMsg =  currentMp.get("warn_disassemble_bonnet").toString();
                                    break;
                                case "2":
                                    warnMsg =  currentMp.get("warn_lever_shearing").toString();
                                    break;
                                case "3":
                                    warnMsg =  currentMp.get("warn_lvd").toString();
                                    break;
                                case "4":
                                    warnMsg =  currentMp.get("warn_overspeed").toString();
                                    break;
                                case "5":
                                    warnMsg =  currentMp.get("warn_gps_lost").toString();
                                    break;
                                case "6":
                                    warnMsg =  currentMp.get("warn_long_time").toString();
                                    break;
                                case "7":
                                    warnMsg =  currentMp.get("warn_route_deviation").toString();
                                    break;
                                case "8":
                                    warnMsg =  currentMp.get("warn_park_long_time").toString();
                                    break;
                            }

                            if (!StringUtils.isEmpty(km.getValue().toString())) {
                                Predicate p = criteriaBuilder.like(root.get("msg").as(String.class), "%" + warnMsg + "%");
                                list.add(p);
                            }

                        }
                    }
                }
                //未删除
                Predicate p1 = criteriaBuilder.isNull(root.get("deletionTime").as(ZonedDateTime.class));
                list.add(p1);
                return criteriaBuilder.and(list.toArray(new Predicate[0]));
            }
        };
        //调用业务层，返回Page
        Page<WarnInfo> warnInfos = warnInfoRepository.findAll(dispatchSpecification, pageable);

        List<WarnInfoDTO> warnInfoDTOS = warnInfos.getContent().stream().
                map(n -> {
                    WarnInfoDTO warnInfoDTO = warnInfoMapper.toDto(n);
//                    warnInfoDTO.setPostionLng(n.getPostionLng());
//                    warnInfoDTO.setPostionLat(n.getPostionLat());
                    extendDispatchInfo(warnInfoDTO);
                    extendHandleUserName(warnInfoDTO);
                    return warnInfoDTO;
                }).collect(Collectors.toList());
        return BaseDTO.createBaseDTO(warnInfos).setFieldList(warnInfoDTOS);
    }


    public BaseDTO sendMessage(String warnId, String phone,String message) {
        WarnInfo info = warnInfoRepository.findOne(warnId);

        String requestUrl ;
        String recipient = phone;
        String username = "SMIC";
        String password = "SMIC@u#^5-9a@fMW";
        String originator = "06201234567";
        String host = "https://sms.minfin.gov.ao/api?action=sendmessage";
        String msg = "notify_success";
        Boolean success = true;
        List<Dictionary> diclist = this.dictionaryRepository.getDictListByType("sms_type");
        for (Dictionary dictionary : diclist) {
            if (dictionary.getItemKey() == "SMS_PASSWORD") {
                password = dictionary.getItemValue();
            }
            if (dictionary.getItemKey() == "SMS_ACCOUNT") {
                username = dictionary.getItemValue();
            }
            if (dictionary.getItemKey() == "SMS_HOST") {
                host = dictionary.getItemValue();
            }
            if (dictionary.getItemKey() == "SMS_ORIGINATOR") {
                originator = dictionary.getItemValue();
            }
        }

        try {
            requestUrl  = host+"&" +
                    "username=" + URLEncoder.encode(username, "UTF-8") +
                    "&password=" + URLEncoder.encode(password, "UTF-8") +
                    "&recipient=" + URLEncoder.encode(recipient, "UTF-8") +
                    "&messagetype=SMS:TEXT" +
                    "&messagedata=" + URLEncoder.encode(message, "UTF-8") +
                    "&originator=" + URLEncoder.encode(originator, "UTF-8") +
                    "&serviceprovider=GSMModem1" +
                    "&responseformat=html";



            URL url = new URL(requestUrl);
            HttpURLConnection uc = (HttpURLConnection)url.openConnection();
            info.setNoticestatus("1");
            System.out.println(uc.getResponseMessage());

            uc.disconnect();


        } catch(Exception ex) {
            info.setNoticestatus("2");
            msg = "notify_failed";
            success = false;
            System.out.println(ex.getMessage());

        }
        info = warnInfoRepository.save(info);

//        String host = "localhost";
//        int port = 9500;
//        String username = "admin";
//        String password = "123123";
//        Boolean success = false;
//        List<Dictionary> diclist = this.dictionaryRepository.getDictListByType("sms_type");
//        for (Dictionary dictionary : diclist) {
//            if (dictionary.getItemKey() == "SMS_PASSWORD") {
//                password = dictionary.getItemValue();
//            }
//            if (dictionary.getItemKey() == "SMS_ACCOUNT") {
//                username = dictionary.getItemValue();
//            }
//            if (dictionary.getItemKey() == "SMS_HOST") {
//                host = dictionary.getItemValue();
//            }
//            if (dictionary.getItemKey() == "SMS_PORT") {
//                port = Integer.parseInt(dictionary.getItemValue());
//            }
//        }
//
//
//        MyOzSmsClient osc = null;
//        String msg = "notify_success";
//        info.setNoticestatus("1");
//        try {
//            osc = new MyOzSmsClient(host, port);
//            osc.login(username, password);
//        } catch (IOException e) {
//            e.printStackTrace();
//        } catch (InterruptedException e) {
//            info.setNoticestatus("0");
//            msg = "uninformed";
//            success = false;
//            e.printStackTrace();
//        }
//
//        if (osc.isLoggedIn()) {
//            try {
//                osc.sendMessage(phone, info.getContainerCode() + "," + info.getLockCode() + ":" + info.getMsg());
//
//
//
//            } catch (UnsupportedEncodingException e) {
//                info.setNoticestatus("2");
//                msg = "notify_failed";
//                success = false;
//                e.printStackTrace();
//
//            }
//        } else {
//            msg = "account_pwd_is_not_correct";
//            success = false;
//        }
//        success = true;
//        info = warnInfoRepository.save(info);


        return BaseDTO.createBaseDTO(info).setMessage(msg).setSuccess(success);
    }


}
